package com.nlp.automata;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/**
 * NFA状态
 * @author ygsong.abcft
 *
 */
public class NFAState implements Comparable<NFAState> {

	private static int COUNT = 0;

	/**
	 * 状态标识，每个NFA状态节点都有唯一的数值标识
	 */
	private int id;

	public int getId() {
		return id;
	}

	/**
	 * 在创建NFA状态对象的时候，通过静态变量生成唯一标识
	 */
	public NFAState() {
		this.id = COUNT++;
	}

	/**
	 * 迁移函数，由于迁移函数需要两个输入：当前状态和输入状态，因此在一个状态对象内部
	 * 迁移函数都是针对对象本身的，只需要输入符号就可以了，这里通过map来实现迁移函数
	 */
	protected Map<Integer, Set<NFAState>> transition = new HashMap<>();

	public Map<Integer, Set<NFAState>> getTransition() {
		return transition;
	}

	/**
	 * 空字符迁移函数，即从当前节点经过空字符输入所能够到达的下一个状态节点
	 */
	protected Set<NFAState> epsilonTransition = new HashSet<>();

	public Set<NFAState> getEpsilonTransition() {
		return epsilonTransition;
	}

	/**
	 * 向迁移函数添加一个映射，不给定下一个状态节点
	 */
	public NFAState addTriansit(int input) {
		return addTriansit(input, new NFAState());
	}

	/**
	 * 向迁移函数添加一个映射，给定下一个状态节点
	 * 
	 * @param input
	 * @param next
	 * @return
	 */
	public NFAState addTriansit(int input, NFAState next) {
		Set<NFAState> states = this.transition.get(input);
		if (states == null) {
			states = new HashSet<>();
			this.transition.put(input, states);
		}
		states.add(next);
		return next;
	}

	/**
	 * 向迁移函数添加一个映射，不给定下一个状态节点
	 */
	public NFAState addTriansit(char input) {
		return addTriansit(input, new NFAState());
	}

	/**
	 * 向迁移函数添加一个映射，给定下一个状态节点
	 */
	public NFAState addTriansit(char input, NFAState next) {
		if (Character.isLetter(input)) {
			this.addTriansit((int) (Character.toUpperCase(input)), next);
			this.addTriansit((int) (Character.toLowerCase(input)), next);
			return next;
		}

		this.addTriansit((int) input, next);
		return next;
	}

	/**
	 * 添加一个空字符的映射
	 */
	public NFAState addTransit(NFAState next) {
		this.epsilonTransition.add(next);
		return next;
	}

	/**
	 * 返回迁移函数
	 * 
	 * @param input
	 * @return
	 */
	public Set<NFAState> getTransition(int input) {
		return this.transition.get(input);
	}

	@Override
	public int compareTo(NFAState o) {
		// TODO Auto-generated method stub
		return 0;
	}

	public Set<NFAState> getNextStates() {
		return getTransition(getId());
	}

}
